<?php

require_rewrite(SYSTEM_PATH . '/config/log_config.php');
require_rewrite(SYSTEM_PATH . 'lib/Log_File.php');
require_rewrite(COMMON_MODULE_MODULE_PATH . 'AccessModule.class.php');

class App extends Etpass_common {

    public $controller_white_list = array();
    public $controller_black_list = array();
    public $noctrl_list = array();
    private $validate = array();

    public function __construct() {
        parent::__construct();
        //公共变量处理
    }

    public function init() {
        set_error_handler(array($this, 'site_error_handler'));
        set_exception_handler(array($this, 'site_exception_handler'));
    }

    public function run() {
        $this->init();

        $controller_pre = $this->_getContronller();
        $controller = ucfirst($controller_pre) . 'Controller';
        $method = $this->_getMethod();

        //黑白名单校验
        if (!in_array($controller, $this->noctrl_list)) {
            if ($this->controller_white_list) {
                if (is_array($this->controller_white_list[$controller])) {
                    if (!in_array($method, $this->controller_white_list[$controller])) {
                        return;
                    }
                } elseif (!in_array($controller, $this->controller_white_list)) {
                    return;
                }
            } elseif ($this->controller_black_list) {
                if (is_array($this->controller_black_list[$controller])) {
                    if (in_array($method, $this->controller_black_list[$controller])) {
                        return;
                    }
                } elseif (in_array($controller, $this->controller_black_list)) {
                    return;
                }
            }
        }
        !$method && $method = 'Index';
        // 访问控制
        if (CONTROL_IP) {
            $access_controller = "";
            $access_module = new AccessModule();
            $access_module->init($controller_pre, $method);
            if ($access_module->check_access()) {
                $access_controller = 'AccessController';
            }
        }

        //用户提交参数过滤
        $_GET['c'] = $controller_pre;
        $_GET['m'] = $method;
        
        if (CHK_GLOBAL) {
            $this->validate = $this->get_validate_config();
            $this->chk_global();
        }
        
        //运行
        if (!empty($access_controller)) {
            $obj = new $access_controller;
            $obj->init($controller_pre, $method);
            $method = "index";
        } else {
            //用户提交参数过滤
            if (class_exists($controller, TRUE)) {
                $obj = new $controller;
            } else {
                
                $error_c = 'PageErrorController';             
            }
        }
        
        if (method_exists($obj, $method)) {
            call_user_func(array(&$obj, $method));
        } else {
            $error_c = 'PageErrorController';
        }
        //执行404页面
        if($error_c){
        	header('HTTP/1.1 404 Not Found');
        	header("status: 404 Not Found");
//             $obj = new $error_c;
//             $obj->page_error();
        }
            

        return;
    }

    /**
     * 自定义的异常处理函数。
     * 在异常未被try/catch捕获时，代码再执行完此函数后终止。
     * @param <type> $exception 被抛出的异常对象
     */
    public function site_exception_handler($exception) {
        //日志
        $format = "system error:  Uncaught exception '%s' in %s: line %s \r\nc:\r\n%s\r\n";
        $msg = sprintf($format, $exception->getMessage(), $exception->getFile(), $exception->getLine(), $exception->getTraceAsString());
        Log_File::writeExecptionLog($msg, true);
        //转向到统一的提示页面
    }

    /**
     * 自定义的错误处理函数。
     * 在系统发生严重错误或者trigger_error()被呼叫时执行。
     * @param <int> $errno 错误的级别，整型。为系统预定义错误代码。
     * @param <string> $errstr 错误信息，字符。
     * @param <string> $errfile 产生错误的文件名，可选。
     * @param <int> $errline 产生错误的代码所在的行数，可选。
     * @param <array> $errcontext 错误的上下文变量数组。手机版新架构测试用
     */
    public function site_error_handler($errno, $errstr = "", $errorfile = "", $errline = 0, $errcontext = array()) {
        //根据错误级别记录日志
        $errno = intval($errno);
        $error_log_level = array(1, 2, 4, 16, 32, 64, 4096);

        //输出 GET POST COOKIE等上下变量
        $context = array();
        $context['_GET'] = isset($errcontext['_nGET']) ? $errcontext['_nGET'] : array();
        $context['_POST'] = isset($errcontext['_nPOST']) ? $errcontext['_nPOST'] : array();
        $context['_COOKIE'] = isset($errcontext['_nCOOKIE']) ? $errcontext['_nCOOKIE'] : array();
        if ($context['_GET'] || $context['_POST'] || $context['_COOKIE']) {
            $errstr .= var_export($context, TRUE);
        }

        if (in_array($errno, $error_log_level)) {
            Log_File::writeSysErrorLog($errno, $errstr, $errorfile, $errline, true);
        }
    }

    private function _getContronller() {

        if ($_GET['c']) {
            return $_GET['c'];
        } else {
            $path = $this->_getpathinfo();
            if ($path['c']) {
                return $path['c'];
            }
//            return NULL;
            return 'index';
        }
    }

    private function _getMethod() {
        if ($_GET['m']) {
            return strtolower($_GET['m']);
        } else {
            $path = $this->_getpathinfo();
            if ($path['m'])
                return strtolower($path['m']);
        }
        return NULL;
    }

    private function _getpathinfo() {

        static $path = NULL;
        if ($path === NULL) {
            $pathinfo = parse_url($_SERVER['REQUEST_URI']);
            $cs = explode('/', $pathinfo['path']);
//            print_r($cs);
            $path = array();
            if ($cs[1]) {
                $path['c'] = $cs[1];
                if ($cs[2])
                    $path['m'] = $cs[2];
            }
            
            
//            $pathinfo = pathinfo($_SERVER['REQUEST_URI']);
//            $cs = explode('/', $pathinfo['dirname']);
//            print_r($cs);
//            $path = array();
//            if ($cs[1]) {
//                $path['c'] = $cs[1];
//                if ($cs[2])
//                    $path['m'] = $cs[2];
//                else
//                    $path['m'] = $pathinfo['basename'];
//            }
            
            
        }
        return $path;
    }

    protected function chk_global() {
        $arr = $this->validate;
        if (!isset($arr['*']) && !empty($arr)) {
            $_nGET = $_GET;
            $_nPOST = $_POST;
            $_nCOOKIE = $_COOKIE;

            $_REQUEST = $_POST = $_GET = $_COOKIE = array();
            foreach ($_nGET as $key => $value) {
                if (isset($arr[$key]['type'])) {
                    $method = 'get' . $arr[$key]['type'];
                    $arr[$key]['param'] = array_merge(array('val' => $value), $arr[$key]['param']);
                    $_GET[$key] = call_user_func_array(array($this, $method), $arr[$key]['param']);
                }
            }
            foreach ($_nPOST as $key => $value) {
                if (isset($arr[$key]['type'])) {
                    $method = 'get' . $arr[$key]['type'];
                    $arr[$key]['param'] = array_merge(array('val' => $value), $arr[$key]['param']);
                    $_POST[$key] = call_user_func_array(array($this, $method), $arr[$key]['param']);
                }
            }
            foreach ($_nCOOKIE as $key => $value) {
                if (isset($arr[$key]['type'])) {
                    if ($arr[$key]['type'] == 'array' && is_array($value)) {
                        foreach ($value as $sub_key => $sub_value) {
                            if (isset($arr[$key]['key'][$sub_key]['type'])) {
                                $sub_method = 'get' . $arr[$key]['key'][$sub_key]['type'];
                                $param = array_merge(array('val' => $sub_value), $arr[$key]['key'][$sub_key]['param']);
                                $_COOKIE[$key][$sub_key] = call_user_func_array(array($this, $sub_method), $param);
                            }
                        }
                    } else {
                        $method = 'get' . $arr[$key]['type'];
                        $arr[$key]['param'] = array_merge(array('val' => $value), $arr[$key]['param']);
                        $_COOKIE[$key] = call_user_func_array(array($this, $method), $arr[$key]['param']);
                    }
                }
            }
        }
    }

    /**
     * 复合参数，
     *
     * @param mixed $val
     * @param str $delimiter
     * @param array $sub
     *
     * @return str
     */
    protected function getmixed($val, $delimiter, $sub) {
        $vals = explode($delimiter, $val);
        $return = array();
        foreach ($vals as $key => $value) {
            if (isset($sub[$key]['type'])) {
                $method = 'get' . $sub[$key]['type'];
                $sub[$key]['param'] = array_merge(array('val' => $value), $sub[$key]['param']);
                $return[$key] = call_user_func_array(array($this, $method), $sub[$key]['param']);
            }
        }
        return implode($delimiter, $return);
    }

    /**
     * 返回一个整型数据
     * @param int $val
     * @return int
     */
    protected function getint($val, $len = 0) {
        $len ? $val = $this->getenstr($val, $len) : $val;
        return intval($val);
    }

    /**
     * 返回一个浮点型数据
     * @param float $val
     * @return float
     */
    protected function getfloat($val) {
        return floatval($val);
    }

    /**
     * 返回一个json数据
     * @param json $val
     * @return json
     */
    protected function getjsonStr($val) {
        return $val;
    }

    /**
     * 返回一个限定长度的英文字符串。
     * @param str $val
     * @param int $len
     * @return str
     */
    protected function getenstr($val, $len = 0) {
        $val = etpass_replace($val);
        if ($len) {
            $val = str_replace(array(' ', '&nbsp;', '&amp;', '&quot;', '&#039;', '&ldquo;', '&rdquo;', '&mdash;', '&lt;', '&gt;', '&middot;', '&hellip;'), array('∵', ' ', '&', '"', "'", '“', '”', '—', '<', '>', '·', '…'), $val);
            $val = substr($val, 0, $len);
            $val = str_replace(array('∵', '&', '"', "'", '“', '”', '—', '<', '>', '·', '…'), array(' ', '&amp;', '&quot;', '&#039;', '&ldquo;', '&rdquo;', '&mdash;', '&lt;', '&gt;', '&middot;', '&hellip;'), $val);
            return $val;
        } else {
            return $val;
        }
    }

    /**
     * 返回一个限定长度的字符串。支持utf-8的中文
     * @param str $val
     * @param int $len
     * @return str
     */
    protected function getstr($val, $len = 0) {
//        return substr($val, 0, $len);
        $val = etpass_replace($val);
        if ($len)
            return Handler_string::utf8_substr($val, $len, '');
        else
            return $val;
    }

    /**
     * 返回枚举类型
     * @param mixed $val
     * @param array $enum
     * @param mixed $length
     * @return mixed
     */
    protected function getenum($val, $enum, $default) {
//        print_r(func_get_args());
        if (in_array($val, $enum)) {
            return $val;
        }
        return $default;
    }

    /**
     * 去除空格
     * @param str $string
     * @return str
     */
    protected function trim($string) {
        $string = preg_replace('/\s(?=\s)/', '', trim($string));
        $string = preg_replace('/[\n\r\t]/', '', $string);
        $string = preg_replace('/\xe3\x80\x80/', '', $string);
        return $string;
    }

    private function get_validate_config() {
        static $config = NULL;
        if ($config === NULL) {
            $config = require SYSTEM_PATH . 'config/validate.config.php';
        }
        return $config;
    }

}

?>